﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PetaPoco;
using System.Collections;
using System.Data;

namespace PetaPoco
{
    public abstract class BaseDataAccess<TEntity> : IDisposable
    {
        #region Private

        private Database _dbReader;
        private Database _dbExecute;
        #endregion

        #region Properties
        protected string ReaderConnectionName
        {
            get
            {
                return ConfigConstant.READER_CONNECTION_NAME;
            }
        }
        protected string ExecuteConnectionName
        {
            get
            {
                return ConfigConstant.WRITE_CONNECTION_NAME;
            }
        }

        protected Database DbExecute
        {
            get
            {
                if (_dbExecute == null) _dbExecute = new Database(ExecuteConnectionName);
                return _dbExecute;
            }
            private set { _dbExecute = value; }
        }

        protected Database DbReader
        {
            get
            {
                if (_dbReader == null) _dbReader = new Database(ReaderConnectionName);
                return _dbReader;
            }
            private set { _dbReader = value; }
        }

        //public void BeginTrans()
        //{
        //    DbExecute.BeginTransaction();
        //}
        //public void CommitTrans()
        //{
        //    DbExecute.CompleteTransaction();
        //}
        //public void Rollback()
        //{
        //    DbExecute.AbortTransaction();
        //}
        #endregion

        #region Construction
        public BaseDataAccess()
        {
        }

        /// <summary>
        /// 读写加入事务
        /// </summary>
        /// <param name="trans">事务</param>
        public BaseDataAccess(Transaction trans)
        {
            if (trans == null) return;

            this._dbExecute = trans.Db;
            this._dbReader = trans.Db;
        }

        public BaseDataAccess(string connectionString)
        {
            this._dbReader = new Database(connectionString);
            this._dbExecute = new Database(connectionString);
        }

        #endregion

        #region 主键获取唯一实体

        public virtual TEntity GetEntity(object primaryKey)
        {
            return DbReader.SingleOrDefault<TEntity>(primaryKey);
        }

        #endregion

        #region 查询条件获取第一个实体

        protected TEntity FirstOrDefault(string sql, params object[] args)
        {
            return DbReader.FirstOrDefault<TEntity>(sql, args);
        }

        protected TEntity FirstOrDefault(Sql sql)
        {
            return DbReader.FirstOrDefault<TEntity>(sql);
        }

        #endregion

        #region 查询条件获取数据列表

        protected virtual List<TEntity> GetList(string sql, params object[] args)
        {
            return DbReader.Fetch<TEntity>(sql, args);
        }
        #endregion

        #region 查询条件获取 Hashtable 列表

        protected virtual List<Hashtable> Hashtables(string sql, params object[] args)
        {
            return DbReader.Hashtables(sql, args);
        }
        #endregion

        #region 分页


        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页数量</param>
        /// <param name="sql">查询语句</param>
        /// <param name="args">传参</param>
        /// <returns>分页结果</returns>
        protected virtual Page<TEntity> PageList(long pageIndex, long pageSize, string sql, params object[] args)
        {
            return DbReader.Page<TEntity>(pageIndex, pageSize, sql, args);
        }

        protected virtual Page<TEntity> PageList(long pageIndex, long pageSize, Sql sql)
        {
            return DbReader.Page<TEntity>(pageIndex, pageSize, sql);
        }

        public virtual PageTable PageList(long pageIndex, long pageSize, List<ScriptSearch> scriptSearchs, string orderBy)
        {
            return DbReader.PageTable<TEntity>(pageIndex, pageSize, scriptSearchs, orderBy);
        }

        #endregion

        #region 查找前几行数据 Tops

        /// <summary>
        /// 查找前几行数据
        /// </summary>
        /// <param name="top">想获取的数据行</param>
        /// <param name="sql"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public List<TEntity> Tops(int top, string sql, params object[] args)
        {
            return DbReader.SkipTake<TEntity>(0, top, sql, args);
        }
        #endregion

        #region 判断数据是否存在 IsExists

        /// <summary>
        /// 判断数据是否存在，如 Col1=@0 AND Col2=@1
        /// </summary>
        /// <param name="sqlCondition">条件(无需带WHERE)</param>
        /// <param name="args">参数</param>
        /// <returns>存在返回true</returns>
        protected virtual bool IsExists(string sqlCondition, params object[] args)
        {
            return DbReader.Exists<TEntity>(sqlCondition, args);
        }
        #endregion

        #region 执行列查询 ExecuteScalar

        protected Nullable<T> ExecuteStructScalar<T>(Sql sql)
            where T : struct
        {
            var result = DbReader.ExecuteScalar<object>(sql);
            if (result == DBNull.Value)
            {
                return null;
            }
            return (T)result;
        }

        /// <summary>
        /// 执行查询，如： SELECT COUNT(*) FROM ...
        /// </summary>
        /// <typeparam name="T">返回的数据类型</typeparam>
        /// <param name="sql"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected T ExecuteScalar<T>(string sql, params object[] args)
        {
            return DbReader.ExecuteScalar<T>(sql, args);
        }
        #endregion

        #region 保存

        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Save(TEntity entity)
        {
            DbExecute.Save(entity);
        }

        /// <summary>
        /// 带事务保存
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="trans"></param>
        public virtual void Save(TEntity entity, Transaction trans)
        {
            if (trans == null)
                this.Save(entity);
            trans.Db.Save(entity);
        }
        #endregion

        #region 录入

        public virtual object Insert(TEntity entity)
        {
            return DbExecute.Insert(entity);
        }

        public virtual object Insert(TEntity entity, Transaction trans)
        {
            if (trans == null)
                return this.Insert(entity);
            return trans.Db.Insert(entity);
        }
        #endregion

        #region 批量录入

        public int MysqlInserts(List<TEntity> entities)
        {
            if (entities.Count < 1) return 0;

            var val = DbExecute.MysqlInserts(entities);
            if (val != entities.Count) throw new Exception("批量录入执行异常, 录入数量与需被录入数量不一致");
            return val;
        }

        public int MysqlInserts(List<TEntity> entities, Transaction trans)
        {
            if (entities.Count < 1) return 0;

            var val = trans.Db.MysqlInserts(entities);
            if (val != entities.Count) throw new Exception("批量录入执行异常, 录入数量与需被录入数量不一致");
            return val;
        }
        #endregion

        #region 更新

        public virtual int Update(TEntity entity, params string[] columns)
        {
            return DbExecute.Update(entity, columns);
        }

        public virtual int Update(TEntity entity)
        {
            return DbExecute.Update(entity);
        }
        public virtual int Update(TEntity entity, Transaction trans)
        {
            if (trans == null)
                return this.Update(entity);
            return trans.Db.Update(entity);
        }

        /// <summary>
        /// 更新指定列
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="columns">要更新的列</param>
        /// <returns>成功返回True</returns>
        public virtual int Update(TEntity entity, IEnumerable<string> columns)
        {
            return DbExecute.Update(entity, columns);
        }

        public virtual int Update(TEntity entity, IEnumerable<string> columns, Transaction trans)
        {
            if (trans == null)
                return this.Update(entity, columns);
            return trans.Db.Update(entity, columns);
        }
        #endregion

        #region 删除

        /// <summary>
        /// 根据主键删除数据
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <returns>成功返回True</returns>
        public virtual bool Delete(object primaryKey)
        {
            return DbExecute.Delete<TEntity>(primaryKey) > 0;
        }

        /// <summary>
        /// 主键删除数据
        /// </summary>
        /// <param name="primaryKey">主键</param>
        /// <param name="trans">事务</param>
        /// <returns>成功返回True</returns>
        public virtual bool Delete(object primaryKey, Transaction trans)
        {
            if (trans == null)
                return this.Delete(primaryKey);
            return trans.Db.Delete<TEntity>(primaryKey) > 0;
        }

        #endregion

        #region 执行sql语句 Execute

        protected virtual int Execute(string sql, params object[] args)
        {
            return DbExecute.Execute(sql, args);
        }
        protected virtual int Execute(Sql sql)
        {
            return DbExecute.Execute(sql);
        }
        protected virtual int Execute(Transaction trans, string sql, params object[] args)
        {
            if (trans == null)
                return this.Execute(sql, args);
            return trans.Db.Execute(sql, args);
        }
        protected virtual int Execute(Transaction trans, Sql sql)
        {
            if (trans == null)
                return this.Execute(sql);
            return trans.Db.Execute(sql);
        }
        #endregion

        #region 事务

        protected Transaction Trans
        {
            get;
            private set;
        }

        public Transaction GetTransaction()
        {
            Trans = (Transaction)this.DbExecute.GetTransaction();
            this._dbExecute = Trans.Db;
            this._dbReader = Trans.Db;
            return Trans;
        }

        public Transaction GetTransaction(IsolationLevel il)
        {
            Trans = (Transaction)this.DbExecute.GetTransaction(il);
            this._dbExecute = Trans.Db;
            this._dbReader = Trans.Db;
            return Trans;
        }
        #endregion

        #region 生成 @0,@1.. 字符串

        /// <summary>
        /// 生成 @0,@1.. 字符串
        /// </summary>
        /// <param name="length">生成长度</param>
        /// <returns>结果字符串</returns>
        /// <author>柯广强 2015.4.17</author>
        protected string GenerateAtString(int length)
        {
            string[] s = new string[length];
            for (int i = 0; i < length; i++)
            {
                s[i] = "@" + i;
            }
            return string.Join(",", s);
        }
        #endregion

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            //if (_dbExecute != null)
            //    _dbExecute.Dispose();

            //if (_dbReader != null)
            //    _dbReader.Dispose();

            //DbExecute = null;
            //DbReader = null;
        }
    }
}
